﻿using System;
using System.Globalization;
using System.Collections.ObjectModel;

namespace Silverlight.SqlStatementEvaluator
{
    /// <summary>
    /// Specifies SQL statement part
    /// </summary>
    internal enum SqlStatementPartEnum
    {
        OrderBy,
        Select,
        Where
    }

    /// <summary>
    /// Analizes SQL statement string
    /// </summary>
    internal class StringAnalizer
    {
        #region Data Fields
        /// <summary>
        /// Ho;ds reference to CharacterProvider
        /// </summary>
        private CharacterProvider _characterProvider;

        /// <summary>
        /// Condition parts
        /// </summary>
        private Collection<StringPart> _stringParts;

        /// <summary>
        /// Condition values
        /// </summary>
        private object[] _values;

        /// <summary>
        /// Sql statement part
        /// </summary>
        private SqlStatementPartEnum _sqlStatementPart;
        #endregion

        #region Events
        #endregion
        
        #region Constructors
        /// <summary>
        /// Default constructor
        /// </summary>
        /// <param name="text">Sql statement part</param>
        /// <param name="sqlStatementPart">Sql statement part type</param>
        /// <param name="values">Condition values</param>
        public StringAnalizer(string text, SqlStatementPartEnum sqlStatementPart, params object[] values)
        {
            // Validate argument
            if (string.IsNullOrEmpty(text))
            {
                throw new ArgumentNullException("text");
            }

            this._characterProvider = new CharacterProvider(text);
            this._stringParts = new Collection<StringPart>();
            this._sqlStatementPart = sqlStatementPart;
            this._values = values;
        }
        #endregion

        #region Properties
        #endregion

        #region Methods
        /// <summary>
        /// Adds part to collection
        /// </summary>
        /// <param name="stringPart">Part for adding</param>
        private void AddToCollection(ref StringPart stringPart)
        {
            // Assign value to part and add it to collection
            this.AssignValue(ref stringPart);
            stringPart.AddedToCollection = true;
            this._stringParts.Add(stringPart);
        }

        /// <summary>
        /// Assignes value to part
        /// </summary>
        /// <param name="stringPart">Part for value assigning</param>
        private void AssignValue(ref StringPart stringPart)
        {
            if (stringPart.Type == StringPartType.Equal
                || stringPart.Type == StringPartType.Grater
                || stringPart.Type == StringPartType.GraterOrEqual
                || stringPart.Type == StringPartType.Less
                || stringPart.Type == StringPartType.LessOrEqual
                || stringPart.Type == StringPartType.Like)
            {
                stringPart.Parameter = this._values[stringPart.ParameterIndex];
            }
        }

        /// <summary>
        /// Parses string text
        /// </summary>
        public Collection<StringPart> Analize()
        {
            // Create string part
            StringPart currentStringPart = new StringPart(this._sqlStatementPart);

            // Get character from provider
            char character = this._characterProvider.Character;

            // Repeat steps till the end of the string
            while (character != '\0')
            {
                // Add character to StringPart
                currentStringPart.Character = character;

                // Check if StringPart is ready
                if (currentStringPart.Ready)
                {
                    // Create new StringPart
                    StringPart nextStringPart = new StringPart(this._sqlStatementPart);
                    nextStringPart.FieldName = currentStringPart.NextPartText;
                    AddToCollection(ref currentStringPart);

                    // Make newly created part as current
                    currentStringPart = nextStringPart;
                }

                this._characterProvider.MoveNext();
                character = this._characterProvider.Character;
            }

            if (!currentStringPart.AddedToCollection & currentStringPart.FieldName.Length > 0)
            {
                // Assign value to part and add it to collection
                currentStringPart.Ready = true;
                AddToCollection(ref currentStringPart);
            }

            return this._stringParts;
        }
        #endregion
    }
}
